Skip to content

docs(openapi): Autofix OpenAPI spec validation errors - #2785

Merged
Pijukatel merged 2 commits into
masterfrom
claude/openapi-errors-fix-xjikyy
Jul 20, 2026
Merged

Pijukatel merged 2 commits into
masterfrom
claude/openapi-errors-fix-xjikyy

Conversation

@Pijukatel

@Pijukatel Pijukatel commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Autogenerated OpenAPI fixes suggestions based on validation errors generated from running API integration tests with OpenAPI validator turned on.

Error log: User-provided production api.log excerpt (SOFT_FAIL response validation errors, Jul 18–20, 2026). The log is not available at a public URL, so the normalized log lines are included below:

Jul 18 00:34:05 apify-api SOFT_FAIL {"errors":[{"message":"no schema defined for status code '402' in the openapi spec","path":"/v2/actors/{actorId}/builds?version=1.0&useCache=false&waitForFinish=180"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":402.0,"url":"/v2/actors/{actorId}/builds?version=1.0&useCache=false&waitForFinish=180"}
Jul 18 02:50:38 apify-api SOFT_FAIL {"errors":[{"message":"no schema defined for status code '404' in the openapi spec","path":"/v2/actor-tasks"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":404.0,"url":"/v2/actor-tasks"}
Jul 20 08:15:38 apify-api SOFT_FAIL {"errors":[{"errorCode":"type.openapi.validation","message":"must be string","path":"/response/data/taggedBuilds/{tag}/buildNumber"},{"errorCode":"type.openapi.validation","message":"must be null","path":"/response/data/taggedBuilds/{tag}"},{"errorCode":"anyOf.openapi.validation","message":"must match a schema in anyOf","path":"/response/data/taggedBuilds/{tag}"},{"errorCode":"type.openapi.validation","message":"must be null","path":"/response/data/taggedBuilds"},{"errorCode":"anyOf.openapi.validation","message":"must match a schema in anyOf","path":"/response/data/taggedBuilds"}],"method":"GET","msg":"Response OpenAPI validation error","statusCode":200.0,"url":"/v2/actors/{actorId}"}
Jul 20 08:47:37 apify-api SOFT_FAIL {"errors":[{"message":"no schema defined for status code '409' in the openapi spec","path":"/v2/actor-tasks/{actorTaskId}"}],"method":"PUT","msg":"Response OpenAPI validation error","statusCode":409.0,"url":"/v2/actor-tasks/{actorTaskId}"}

A follow-up regression run of the integration tests with the fixed spec (validator run results) surfaced one additional response validation error, fixed as the fifth fix below.

apify-core version: https://github.com/apify/apify-core/commit/48a50ff1c30b82ade5283e5465ef63a7ec09095b

Stop reason: All 4 unique errors from the provided log are fixed, plus 1 new response validation error found in the regression run. The original 4 errors cannot be reproduced in the PR test environment (they come from production traffic and legacy data), so they were verified against apify-core source instead. The regression run with the fixed spec passed (status SUCCESS) and its api.log contains no response validation errors caused by these changes; the remaining request validation errors in that log are deliberate malformed-request tests or pre-existing issues unrelated to this diff (see Unfixed errors).

Detailed changes description

Error fixes

Add 402 (Payment Required) response to Build Actor endpoint

  • Files: apify-api/openapi/paths/actors/acts@{actorId}@builds.yaml:123
  • Error: {"errors":[{"message":"no schema defined for status code '402' in the openapi spec","path":"/v2/actors/{actorId}/builds?version=1.0&useCache=false&waitForFinish=180"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":402}
  • Root cause: POST /v2/actors/{actorId}/builds enforces the account memory and concurrent-runs limits before creating the build and throws memory-limit-exceeded/concurrent-runs-limit-exceeded errors with HTTP 402, but the spec did not document a 402 response. Reused the PaymentRequired response component, consistent with the run Actor endpoints that document 402 for the same limit checks.
  • Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/packages/actor-server/src/actor_jobs/actor_jobs.server.ts#L1269

Add 404 (Not Found) response to Create task endpoint

Allow null buildNumber in tagged builds of the Actor object

  • Files: apify-api/openapi/components/schemas/actors/TaggedBuildInfo.yaml:10
  • Error: {"errors":[{"errorCode":"type.openapi.validation","message":"must be string","path":"/response/data/taggedBuilds/{tag}/buildNumber"},{"errorCode":"anyOf.openapi.validation","message":"must match a schema in anyOf","path":"/response/data/taggedBuilds/{tag}"}],"method":"GET","msg":"Response OpenAPI validation error","statusCode":200,"url":"/v2/actors/{actorId}"}
  • Root cause: GET /v2/actors/{actorId} builds the taggedBuilds map via transformActor(), which computes buildNumber as buildOrVersionNumberIntToStr(buildNumberInt) with return type string | null; for legacy builds without a valid buildNumberInt the value is null, while the spec allowed only a string. Allowed null for buildNumber (the pattern keyword only applies to string values, so it keeps validating real build numbers).
  • Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/packages/actor/src/actors/actors.both.ts#L113

Add 409 (Conflict) response to Update task endpoint

  • Files: apify-api/openapi/paths/actor-tasks/actor-tasks@{actorTaskId}.yaml:104
  • Error: {"errors":[{"message":"no schema defined for status code '409' in the openapi spec","path":"/v2/actor-tasks/{actorTaskId}"}],"method":"PUT","msg":"Response OpenAPI validation error","statusCode":409}
  • Root cause: PUT /v2/actor-tasks/{actorTaskId} throws actor-task-name-not-unique with HTTP 409 when renaming a task to a name already used by another task of the same user (Mongo duplicate key on userId+nameLowerCase), but the spec did not document a 409 response. Reused the Conflict response component, matching POST /v2/actor-tasks which already documents 409 for the same uniqueness constraint.
  • Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/api/src/routes/actor_tasks/actor_task.ts#L151

Add cannot-monetize-without-payout-billing-info to ErrorType enum

  • Files: apify-api/openapi/components/schemas/common/ErrorType.yaml:68
  • Error: {"url":"/v2/actors/{actorId}","method":"PUT","statusCode":400,"errors":[{"message":"must be equal to one of the allowed values: 3d-secure-auth-failed, access-right-already-exists, ...","errorCode":"enum.openapi.validation","path":"/response/error/type"}]} (from the regression run log)
  • Root cause: PUT /v2/actors/{actorId} with a paid pricing model rejects the update with HTTP 400 and error type cannot-monetize-without-payout-billing-info when the Actor owner has no payout billing info set (thrown by checkAndSanitizePricingInfosModifier), but this error type was missing from the ErrorType enum shared by all error responses.
  • Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/api/src/lib/paid_actors_helpers.ts#L364

Refactoring

None - only the minimum necessary response/schema additions were made.

Unfixed errors

Out of scope errors

Unknown query parameter standbyDeployment on run Actor endpoint

  • Error: {"url":"/v2/actors/{actorId}/runs?standbyDeployment=SINGLE_TENANT&memory=1024&build=latest","method":"POST","errors":[{"message":"Unknown query parameter 'standbyDeployment'","path":"/query/standbyDeployment"}]} (request validation, regression run log)
  • Root cause: ApifyClient 2.23.4 sends a real standbyDeployment query parameter that is not yet documented on POST /v2/actors/{actorId}/runs. Documenting it requires product input on the parameter's contract, which is beyond this autofix PR.

Undocumented endpoint GET /v2/actors/{actorId}/oauth-connections

  • Error: {"url":"/v2/actors/{actorId}/oauth-connections","method":"GET","errors":[{"message":"not found","path":"/actors/{actorId}/oauth-connections"}]} (request validation, regression run log)
  • Root cause: The endpoint exists in apify-core (src/api/src/routes/actors/oauth_connection_list.ts) but has no path in the OpenAPI spec. Adding a whole new documented endpoint is beyond this autofix PR.

Deliberate malformed-request tests and internal-only paths

  • Error: Remaining request validation errors in the regression run log: invalid input/options/generalAccess/eventTypes/filter/handledAt values, unsupported media types, invalid HTTP methods, missing required parameters, and probes of internal paths (/v2/meta/_telemetry-test, /v2/openapi.json, /v2/browser-info?method=...).
  • Root cause: Integration tests intentionally send malformed requests to verify error handling, and some internal/telemetry paths are deliberately absent from the public spec. Per the workflow rules, specs must not be changed to accommodate intentionally invalid requests.

Issues

Partially implements: #2286

…ilds buildNumber

Error: {"errors":[{"message":"no schema defined for status code '402' in the openapi spec","path":"/v2/actors/{actorId}/builds?version=1.0&useCache=false&waitForFinish=180"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":402}
Files: apify-api/openapi/paths/actors/acts@{actorId}@builds.yaml:123
Root cause: POST /v2/actors/{actorId}/builds enforces account memory and concurrent-runs limits before creating the build and throws memory-limit-exceeded/concurrent-runs-limit-exceeded errors with HTTP 402, but the spec did not document a 402 response. Reused the PaymentRequired response component, consistent with the run Actor endpoints that document 402 for the same limit checks.
Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/packages/actor-server/src/actor_jobs/actor_jobs.server.ts#L1269

Error: {"errors":[{"message":"no schema defined for status code '404' in the openapi spec","path":"/v2/actor-tasks"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":404}
Files: apify-api/openapi/paths/actor-tasks/actor-tasks.yaml:142
Root cause: POST /v2/actor-tasks looks up the Actor referenced by actId in the request payload and throws record-not-found with HTTP 404 when that Actor does not exist or is removed, but the spec did not document a 404 response. Reused the NotFound response component.
Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/api/src/routes/actor_tasks/actor_task_list.ts#L190

Error: {"errors":[{"errorCode":"type.openapi.validation","message":"must be string","path":"/response/data/taggedBuilds/{tag}/buildNumber"},{"errorCode":"anyOf.openapi.validation","message":"must match a schema in anyOf","path":"/response/data/taggedBuilds/{tag}"}],"method":"GET","msg":"Response OpenAPI validation error","statusCode":200,"url":"/v2/actors/{actorId}"}
Files: apify-api/openapi/components/schemas/actors/TaggedBuildInfo.yaml:10
Root cause: GET /v2/actors/{actorId} builds the taggedBuilds map via transformActor(), which computes buildNumber as buildOrVersionNumberIntToStr(buildNumberInt) with return type string | null; for legacy builds without a valid buildNumberInt the value is null, while the spec allowed only a string. Allowed null for buildNumber (the pattern keyword only applies to string values in JSON Schema).
Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/packages/actor/src/actors/actors.both.ts#L113

Error: {"errors":[{"message":"no schema defined for status code '409' in the openapi spec","path":"/v2/actor-tasks/{actorTaskId}"}],"method":"PUT","msg":"Response OpenAPI validation error","statusCode":409}
Files: apify-api/openapi/paths/actor-tasks/actor-tasks@{actorTaskId}.yaml:104
Root cause: PUT /v2/actor-tasks/{actorTaskId} throws actor-task-name-not-unique with HTTP 409 when renaming a task to a name already used by another task of the same user (Mongo duplicate key on userId+nameLowerCase), but the spec did not document a 409 response. Reused the Conflict response component, matching POST /v2/actor-tasks which already documents 409 for the same uniqueness constraint.
Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/api/src/routes/actor_tasks/actor_task.ts#L151

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011VY4n4eTrXwjwT4CMsHPJD
@github-actions github-actions Bot added this to the 145th sprint - Tooling team milestone Jul 20, 2026
@github-actions github-actions Bot added the t-tooling Issues with this label are in the ownership of the tooling team. label Jul 20, 2026
@apify-service-account

apify-service-account commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

🗑️ Preview for this PR was deleted.

@apify-service-account

Copy link
Copy Markdown
Contributor

Important

Action required — @Pijukatel please coordinate this docs PR with the Python API client PR linked below.

Because this PR modifies the OpenAPI specification, the generated models in apify-client-python must be regenerated to stay in sync. This has already been done automatically:

A companion PR has been opened in apify-client-python with the regenerated models: apify/apify-client-python#960

  • Please make sure to review and merge both PRs together to keep the OpenAPI spec and API clients in sync.
  • You can ask for review and help from the Tooling team if needed.

@Pijukatel Pijukatel added the adhoc Ad-hoc unplanned task added during the sprint. label Jul 20, 2026
@Pijukatel
Pijukatel requested a review from vdusek July 20, 2026 09:28
@Pijukatel
Pijukatel marked this pull request as ready for review July 20, 2026 09:28
…rType enum

Error: {"url":"/v2/actors/{actorId}","method":"PUT","statusCode":400,"errors":[{"message":"must be equal to one of the allowed values: 3d-secure-auth-failed, access-right-already-exists, ...","errorCode":"enum.openapi.validation","path":"/response/error/type"}]}
Files: apify-api/openapi/components/schemas/common/ErrorType.yaml:68
Root cause: PUT /v2/actors/{actorId} with a paid pricing model rejects the update with HTTP 400 and error type cannot-monetize-without-payout-billing-info when the owner has no payout billing info set (thrown by checkAndSanitizePricingInfosModifier), but this error type was missing from the ErrorType enum used by all error responses.
Reference: https://github.com/apify/apify-core/tree/48a50ff1c30b82ade5283e5465ef63a7ec09095b/src/api/src/lib/paid_actors_helpers.ts#L364

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011VY4n4eTrXwjwT4CMsHPJD
@apify-service-account

Copy link
Copy Markdown
Contributor

Important

Action required — @Pijukatel please coordinate this docs PR with the Python API client PR linked below.

Because this PR modifies the OpenAPI specification, the generated models in apify-client-python must be regenerated to stay in sync. This has already been done automatically:

The companion apify-client-python PR has been updated with the latest spec changes: apify/apify-client-python#960

  • Please make sure to review and merge both PRs together to keep the OpenAPI spec and API clients in sync.
  • You can ask for review and help from the Tooling team if needed.

@Pijukatel
Pijukatel merged commit 7c2d71f into master Jul 20, 2026
18 checks passed
@Pijukatel
Pijukatel deleted the claude/openapi-errors-fix-xjikyy branch July 20, 2026 09:48
vdusek pushed a commit to apify/apify-client-python that referenced this pull request Jul 20, 2026
…de (#960)

- Updates the auto-generated Pydantic models and TypedDicts based on the
proposed OpenAPI specification changes.
- Based on apify-docs PR
[#2785](apify/apify-docs#2785).
Pijukatel added a commit that referenced this pull request Jul 22, 2026
## Summary
Autogenerated OpenAPI fixes suggestions based on validation errors
generated from running API integration tests with OpenAPI validator
turned on.

**Error log:** User-provided production `api.log` excerpt (SOFT_FAIL
response validation errors, Jul 16–21, 2026). The log is not available
at a public URL, so the normalized log lines are included below:

```text
Jul 16 10:34:11 apify-api SOFT_FAIL {"errors":[{"errorCode":"required.openapi.validation","message":"must have required property 'requestUrl'","path":"/response/data/requestUrl"}],"method":"GET","msg":"Response OpenAPI validation error","statusCode":200.0,"url":"/v2/webhooks/{webhookId}"}
Jul 20 15:56:30 apify-api SOFT_FAIL {"errors":[{"message":"no schema defined for status code '402' in the openapi spec","path":"/v2/actor-tasks/{actorTaskId}/run-sync?timeout=300&memory=1024&maxItems=20&build=latest&outputRecordKey=OUTPUT&webhooks="}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":402.0,"url":"/v2/actor-tasks/{actorTaskId}/run-sync?timeout=300&memory=1024&maxItems=20&build=latest&outputRecordKey=OUTPUT&webhooks="}
Jul 21 03:20:22 apify-api SOFT_FAIL {"errors":[{"errorCode":"type.openapi.validation","message":"must be string","path":"/response/data/webhook/requestUrl"},{"errorCode":"type.openapi.validation","message":"must be null","path":"/response/data/webhook"},{"errorCode":"anyOf.openapi.validation","message":"must match a schema in anyOf","path":"/response/data/webhook"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":201.0,"url":"/v2/webhooks/{webhookId}/test?token=[REDACTED]"}
Jul 21 18:01:10 apify-api SOFT_FAIL {"errors":[{"message":"no schema defined for status code '408' in the openapi spec","path":"/v2/actor-tasks/{actorTaskId}/run-sync?token=[REDACTED]&outputRecordKey=OUTPUT"}],"method":"POST","msg":"Response OpenAPI validation error","statusCode":408.0,"url":"/v2/actor-tasks/{actorTaskId}/run-sync?token=[REDACTED]&outputRecordKey=OUTPUT"}
```

**apify-core version:**
apify/apify-core@446d6fa

**Stop reason:** All 4 unique errors from the provided log that are
still present on `master` are fixed. The remaining 4 unique errors in
the log were already fixed on `master` by #2785 (the log lines predate
that merge, see Out of scope errors). The original errors cannot be
reproduced in the PR test environment (they come from production
traffic: non-HTTP webhooks, platform usage limits, sync-run timeouts),
so they were verified against apify-core source instead. A regression
run of the integration tests with the fixed spec completed with status
SUCCESS ([validator run
results](https://apify-pr-test-env-logs.s3.us-east-1.amazonaws.com/apify/apify-core/27741/results-44f0a8f7474fa5f462e4e79633eec56943d63a3a.html))
and its api.log contains zero response validation errors; the remaining
request validation errors in that log are deliberate malformed-request
tests or pre-existing request-side spec gaps unrelated to this diff.

## Detailed changes description
### Error fixes

#### Webhook object no longer requires `requestUrl`
- **Files:**
`apify-api/openapi/components/schemas/webhooks/Webhook.yaml:2`
- **Error:** `must have required property 'requestUrl'` at
`/response/data/requestUrl`, `GET /v2/webhooks/{webhookId}`, status 200
- **Root cause:** `requestUrl` is optional in apify-core and enforced
only for webhooks with actionType `HTTP_REQUEST`. Webhooks with other
action types (Slack message, Google Mail, Google Drive, GitHub issue)
are stored without `requestUrl`, and the API response projection (lodash
`pick`) omits missing keys, so the endpoint legitimately returns a
webhook object without `requestUrl`. A clarifying description was added
to the property.
- **Reference:**
https://github.com/apify/apify-core/tree/446d6faa5a503ddb64447c4b6b758a811b11b397/src/packages/schemas/src/webhooks.ts#L315

#### Webhook summary in webhook dispatch allows null `requestUrl`
- **Files:**
`apify-api/openapi/components/schemas/webhook-dispatches/WebhookDispatchWebhookSummary.yaml:10`
- **Error:** `must be string` at `/response/data/webhook/requestUrl`,
`POST /v2/webhooks/{webhookId}/test`, status 201
- **Root cause:** The test-webhook endpoint embeds the stored webhook
into the created dispatch and the response projection includes
`webhook.requestUrl`. Webhook create/update accepts `requestUrl` as
nullish (`z.string().nullish()`), so non-HTTP webhooks can be stored
with an explicit `null` value, which is then returned inside the
dispatch's webhook summary. The type was widened to `[string, "null"]`
and a clarifying description was added to the property.
- **Reference:**
https://github.com/apify/apify-core/tree/446d6faa5a503ddb64447c4b6b758a811b11b397/src/packages/zod-types/src/common/webhooks.ts#L57

#### Add 402 response to `POST /v2/actor-tasks/{actorTaskId}/run-sync`
- **Files:**
`apify-api/openapi/paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync.yaml:144`
- **Error:** `no schema defined for status code '402' in the openapi
spec`, `POST /v2/actor-tasks/{actorTaskId}/run-sync`, status 402 (3
occurrences in the log)
- **Root cause:** Launching a task run enforces platform usage limits
which throw 402 Payment Required errors (Actor memory limit exceeded,
concurrent runs limit exceeded, not enough usage to run paid Actor).
Sibling run-sync endpoints already document 402 via the shared
`PaymentRequired` response component.
- **Reference:**
https://github.com/apify/apify-core/tree/446d6faa5a503ddb64447c4b6b758a811b11b397/src/packages/errors/src/errors/actor.ts#L5

#### Add 408 response to `POST /v2/actor-tasks/{actorTaskId}/run-sync`
- **Files:**
`apify-api/openapi/paths/actor-tasks/actor-tasks@{actorTaskId}@run-sync.yaml:152`
- **Error:** `no schema defined for status code '408' in the openapi
spec`, `POST /v2/actor-tasks/{actorTaskId}/run-sync`, status 408
- **Root cause:** The run-sync handler throws `run-timeout-exceeded`
with status 408 when the run does not reach a terminal status within the
maximum synchronous wait time. The GET operation of the same path and
all sibling run-sync endpoints already document 408 via the shared
`Timeout` response component.
- **Reference:**
https://github.com/apify/apify-core/tree/446d6faa5a503ddb64447c4b6b758a811b11b397/src/api/src/routes/actor_tasks/run_sync.ts#L68

### Refactoring
None. Only shared response components (`PaymentRequired.yaml`,
`Timeout.yaml`) are re-used; no structural changes.

## Unfixed errors
### Out of scope errors
#### `POST /v2/actors/{actorId}/builds` — no schema for status 402
- **Error:** `no schema defined for status code '402' in the openapi
spec`, status 402 (Jul 18 00:34:05)
- **Root cause:** Already fixed on `master` by #2785 (merged Jul 20);
the log line predates the merge.

#### `POST /v2/actor-tasks` — no schema for status 404
- **Error:** `no schema defined for status code '404' in the openapi
spec`, status 404 (Jul 18 02:50:38)
- **Root cause:** Already fixed on `master` by #2785; the log line
predates the merge.

#### `GET /v2/actors/{actorId}` — `taggedBuilds` `buildNumber` type
error
- **Error:** `must be string` at
`/response/data/taggedBuilds/{tag}/buildNumber`, status 200 (Jul 20
08:15:38)
- **Root cause:** Already fixed on `master` by #2785 (`buildNumber` made
nullable); the log line predates the merge.

#### `PUT /v2/actor-tasks/{actorTaskId}` — no schema for status 409
- **Error:** `no schema defined for status code '409' in the openapi
spec`, status 409 (Jul 20 08:47:37)
- **Root cause:** Already fixed on `master` by #2785; the log line
predates the merge.

## Issues
Partially implements: #2286

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

adhoc Ad-hoc unplanned task added during the sprint. t-tooling Issues with this label are in the ownership of the tooling team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants